import {
    Injectable,
    NestInterceptor,
    ExecutionContext,
    CallHandler,
    Logger,
    BadRequestException,
    HttpStatus
} from '@nestjs/common';
import { Request, Response } from 'express';
import { Observable, throwError, from } from 'rxjs';
import { catchError, mergeMap, tap } from 'rxjs/operators';
import { Reflector } from '@nestjs/core';
import { BaseDao } from '@/common/baseDao/base.service'
import { LOGGING_KEY } from './logger.decorator';
import { v4 as uuidv4 } from 'uuid';

import * as fs from 'fs';
import * as path from 'path';

@Injectable()
export class LoggingInterceptor implements NestInterceptor {
    private readonly logger = new Logger(LoggingInterceptor.name);
    private logFilePath: string;

    constructor(private reflector: Reflector, private baseDao: BaseDao) { }

    intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
        const isLoggingMethod = this.reflector.get<boolean>(LOGGING_KEY, context.getHandler());
        const isLoggingController = this.reflector.get<boolean>(LOGGING_KEY, context.getClass());
        const request = context.switchToHttp().getRequest<Request>();
        const response = context.switchToHttp().getResponse<Response>();
        const requestId = uuidv4();
        request['requestId'] = requestId;
        if (isLoggingMethod || isLoggingController) {
            const { method, originalUrl, headers } = request;
            // const logMessage = `Url=> ${originalUrl}\nMethods=> ${method}\nHeaders=>${JSON.stringify(headers)}`;
            // this.logger.log(logMessage);

            const params = JSON.stringify(request.params);
            const query = JSON.stringify(request.query);
            const body = JSON.stringify(request.body);
            const requestData = {
                params,
                query,
                body
            };

            return from(
                this.baseDao.add({
                    dbName: "quick-log",
                    dataJson: {
                        data: requestData,
                        requestId,
                        $url: originalUrl,
                        method,
                        headers,
                    },
                })
            ).pipe(
                mergeMap(() => 
                    next.handle().pipe(
                        mergeMap(async (data) => {
                            try {
                                // 这里可以获取到响应数据并进行更新
                                await this.baseDao.update({
                                    dbName: "quick-log",
                                    whereJson: {
                                        requestId,
                                    },
                                    dataJson: {
                                        statusCode: response.statusCode, // 获取响应状态码
                                        responseBody: JSON.stringify(data.data?.rows || data.data), // 响应体数据
                                    },
                                });
                                return data; // 返回响应数据
                            } catch (error) {
                                // 如果更新日志时发生错误，抛出 BadRequestException
                                console.log("更新日志发生错误", error);
                                 throw new BadRequestException(error);
                            }
                        })
                    )
                ), // 等待日志操作完成后再继续处理请求
                catchError(async (error) => {
                    // 处理其他错误
                    console.log("处理其他错误", error);
                    await this.baseDao.update({
                        dbName: "quick-log",
                        whereJson: {
                            requestId,
                        },
                        dataJson: {
                            statusCode: HttpStatus.BAD_REQUEST,
                            responseBody: error['message']
                        }
                    });
                    throw new BadRequestException(error);
                }),
            );
        }
        return next.handle(); // 如果不需要日志，直接处理请求
    }

    // 日志写入本地log文件
    private async writeLog(logData: any) {
        const message = `Request=> ${JSON.stringify(logData.request)}\nResponse=> ${JSON.stringify(logData.response)}\n`;
        if (process.env.NODE_ENV === 'development') {
            this.logFilePath = path.join(__dirname, '..', '..', 'log', 'request.log');
        } else {
            this.logFilePath = path.join(__dirname, 'log', 'request.log'); // 假设打包后在同一目录下
        }

        fs.mkdir(path.dirname(this.logFilePath), { recursive: true }, (err) => {
            if (err) {
                return;
            }

            fs.appendFile(this.logFilePath, message, (err) => {
                if (err) {
                    // 处理错误
                }
            });
        });
    }
}
